{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "676b07a5-460a-4e48-b227-3d8678b9e5a9",
   "metadata": {},
   "source": [
    "# Python 异常处理详解\n",
    "\n",
    "## 1. 异常的概念\n",
    "\n",
    "### 1.1 什么是异常？\n",
    "\n",
    "- **定义**：异常是程序在执行过程中发生的错误事件，例如除以零、访问不存在的文件或输入无效数据等。\n",
    "- **作用**：通过异常处理，可以捕获这些错误并采取适当措施，避免程序意外终止，同时提供友好的错误提示。\n",
    "\n",
    "### 1.2 常见的异常类型\n",
    "\n",
    "Python 内置了许多异常类型，以下是一些常见的例子：\n",
    "\n",
    "- `ZeroDivisionError`：除以零。\n",
    "- `FileNotFoundError`：尝试打开不存在的文件。\n",
    "- `IndexError`：访问列表中不存在的索引。\n",
    "- `KeyError`：访问字典中不存在的键。\n",
    "- `ValueError`：传递了不合适的值（如将字符串转为整数时输入非数字）。\n",
    "- `TypeError`：操作或函数应用于不合适的类型。\n",
    "\n",
    "### 1.3 异常处理的重要性\n",
    "\n",
    "- 增强程序的健壮性，避免因小错误导致程序崩溃。\n",
    "- 提供明确的错误信息，便于调试和优化代码。\n",
    "- 提升用户体验，通过友好提示替代冷冰冰的崩溃。\n",
    "\n",
    "---\n",
    "\n",
    "## 2. 异常的捕获与处理\n",
    "\n",
    "### 2.1 `try-except` 块\n",
    "\n",
    "- **语法**：\n",
    "\n",
    "  ```python\n",
    "  try:\n",
    "      # 可能引发异常的代码\n",
    "  except 异常类型:\n",
    "      # 处理异常的代码\n",
    "  ```\n",
    "\n",
    "- **讲解**：\n",
    "\n",
    "  - `try` 块中放置可能出现异常的代码。\n",
    "  - 如果 `try` 块中的代码引发异常，程序会跳转到对应的 `except` 块执行。\n",
    "  - `except` 指定要捕获的异常类型。\n",
    "\n",
    "#### 示例代码"
   ]
  },
  {
   "cell_type": "code",
   "id": "ea41ee38-c394-428b-94d9-c6b6b30f2bfb",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-24T13:14:42.290609Z",
     "start_time": "2025-02-24T13:14:42.288080Z"
    }
   },
   "source": [
    "try:\n",
    "    result = 10 / 0\n",
    "except ZeroDivisionError:\n",
    "    print(\"错误：除以零！\")  # 输出: 错误：除以零！"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "错误：除以零！\n"
     ]
    }
   ],
   "execution_count": 1
  },
  {
   "cell_type": "markdown",
   "id": "e750c2bb-fa54-43f4-b1ef-1be01d16f3c9",
   "metadata": {},
   "source": [
    "- **说明**：尝试执行 `10 / 0` 会引发 `ZeroDivisionError`，`except` 块捕获该异常并打印提示。\n",
    "\n",
    "### 2.2 捕获多个异常\n",
    "\n",
    "- **语法**：\n",
    "\n",
    "  ```python\n",
    "  try:\n",
    "      # 可能引发多种异常的代码\n",
    "  except (异常类型1, 异常类型2):\n",
    "      # 处理这些异常的代码\n",
    "  ```\n",
    "\n",
    "- **讲解**：一个 `except` 块可以捕获多种异常类型，用括号列出。\n",
    "\n",
    "#### 示例代码"
   ]
  },
  {
   "cell_type": "code",
   "id": "495aa018-0697-4f52-9324-133a33b68cf6",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-24T13:14:46.778134Z",
     "start_time": "2025-02-24T13:14:42.298074Z"
    }
   },
   "source": [
    "try:\n",
    "    num = int(input(\"请输入一个数字：\"))\n",
    "    result = 10 / num\n",
    "except (ValueError, ZeroDivisionError):\n",
    "    print(\"输入无效或除以零！\")"
   ],
   "outputs": [],
   "execution_count": 2
  },
  {
   "cell_type": "markdown",
   "id": "86bc7211-5176-4a7d-8705-37dd9e0f6919",
   "metadata": {},
   "source": [
    "- **说明**：捕获 `ValueError`（输入非数字）和 `ZeroDivisionError`（输入 0）。\n",
    "\n",
    "### 2.3 获取异常信息\n",
    "\n",
    "- **语法**：\n",
    "\n",
    "  ```python\n",
    "  try:\n",
    "      # 代码\n",
    "  except 异常类型 as e:\n",
    "      # 使用 e 获取异常信息\n",
    "  ```\n",
    "\n",
    "- **讲解**：通过 `as e` 将异常对象赋值给变量 `e`，可以访问详细的错误信息。\n",
    "\n",
    "#### "
   ]
  },
  {
   "cell_type": "code",
   "id": "f23cc96c-1997-43ca-8a46-ccd3c126fd5c",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-24T13:14:46.874271Z",
     "start_time": "2025-02-24T13:14:46.872713Z"
    }
   },
   "source": [
    "try:\n",
    "    result = 10 / 0\n",
    "except ZeroDivisionError as e:\n",
    "    print(f\"错误：{e}\")  # 输出: 错误：division by zero"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "错误：division by zero\n"
     ]
    }
   ],
   "execution_count": 3
  },
  {
   "cell_type": "markdown",
   "id": "4fa3c40c-e46c-4226-9bee-b8416abbdfd4",
   "metadata": {},
   "source": [
    "## 3. `else` 和 `finally` 块\n",
    "\n",
    "### 3.1 `else` 块\n",
    "\n",
    "- **作用**：在 `try` 块没有引发异常时执行。\n",
    "\n",
    "- **语法**：\n",
    "\n",
    "  ```python\n",
    "  try:\n",
    "      # 代码\n",
    "  except 异常类型:\n",
    "      # 处理异常\n",
    "  else:\n",
    "      # 无异常时执行\n",
    "  ```\n",
    "\n",
    "#### 示例代码"
   ]
  },
  {
   "cell_type": "code",
   "id": "c8d3e652-61ed-4ef0-9f15-040ce90b5ddf",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-24T13:14:47.868060Z",
     "start_time": "2025-02-24T13:14:46.879914Z"
    }
   },
   "source": [
    "try:\n",
    "    num = int(input(\"请输入一个数字：\"))\n",
    "except ValueError:\n",
    "    print(\"输入的不是数字！\")\n",
    "else:\n",
    "    print(f\"你输入了：{num}\")"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "输入的不是数字！\n"
     ]
    }
   ],
   "execution_count": 4
  },
  {
   "cell_type": "markdown",
   "id": "12fdb9b6-5a59-4482-9a5b-d114124a63c9",
   "metadata": {},
   "source": [
    "- **说明**：如果输入有效，`else` 块会执行；否则，`except` 捕获 `ValueError`。\n",
    "\n",
    "### 3.2 `finally` 块\n",
    "\n",
    "- **作用**：无论是否发生异常，`finally` 块中的代码都会执行。\n",
    "\n",
    "- **语法**：\n",
    "\n",
    "  ```python\n",
    "  try:\n",
    "      # 代码\n",
    "  except 异常类型:\n",
    "      # 处理异常\n",
    "  finally:\n",
    "      # 始终执行\n",
    "  ```\n",
    "\n",
    "- **讲解**：常用于清理资源（如关闭文件）。\n",
    "\n",
    "#### 示例代码"
   ]
  },
  {
   "cell_type": "code",
   "id": "c25e8662-71c5-428c-9086-1e500944b5d1",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-24T13:14:47.885074Z",
     "start_time": "2025-02-24T13:14:47.882387Z"
    }
   },
   "source": [
    "try:\n",
    "    f = open(\"data.txt\", \"r\")\n",
    "    content = f.read()\n",
    "except FileNotFoundError:\n",
    "    print(\"文件未找到\")\n",
    "finally:\n",
    "    print(\"关闭文件\")\n",
    "    if 'f' in locals():\n",
    "        f.close()  # 只有在文件成功打开时才关闭"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "文件未找到\n",
      "关闭文件\n"
     ]
    }
   ],
   "execution_count": 5
  },
  {
   "cell_type": "markdown",
   "id": "5e72757d-cd56-4297-8ee9-95e07d1064e8",
   "metadata": {},
   "source": [
    "- **说明**：无论文件是否存在，`finally` 块都会执行。\n",
    "\n",
    "---\n",
    "\n",
    "## 4. 抛出异常\n",
    "\n",
    "### 4.1 使用 `raise` 抛出异常\n",
    "\n",
    "- **语法**：\n",
    "\n",
    "  ```python\n",
    "  raise 异常类型(\"错误信息\")\n",
    "  ```\n",
    "\n",
    "- **讲解**：手动抛出异常，通常用于检查特定条件并提前终止程序。\n",
    "\n",
    "#### 示例代码"
   ]
  },
  {
   "cell_type": "code",
   "id": "20093e33-85ac-4c37-972f-6452d396b3a4",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-24T13:14:47.910649Z",
     "start_time": "2025-02-24T13:14:47.908392Z"
    }
   },
   "source": [
    "def check_age(age):\n",
    "    if age < 18:\n",
    "        raise ValueError(\"年龄必须大于或等于18\")\n",
    "    else:\n",
    "        print(\"年龄合法\")\n",
    "\n",
    "try:\n",
    "    check_age(15)\n",
    "except ValueError as e:\n",
    "    print(f\"错误：{e}\")  # 输出: 错误：年龄必须大于或等于18"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "错误：年龄必须大于或等于18\n"
     ]
    }
   ],
   "execution_count": 6
  },
  {
   "cell_type": "markdown",
   "id": "deba9ca8-dc29-45ac-8a4e-4ad0f1285c93",
   "metadata": {},
   "source": [
    "## 5. 自定义异常\n",
    "\n",
    "### 5.1 自定义异常类\n",
    "\n",
    "- **定义**：通过继承 `Exception` 类创建特定异常。\n",
    "\n",
    "- **语法**：\n",
    "\n",
    "  ```python\n",
    "  class 自定义异常名(Exception):\n",
    "      pass\n",
    "  ```\n",
    "\n",
    "#### 示例代码"
   ]
  },
  {
   "cell_type": "code",
   "id": "c328f96b-df4c-4fb8-8818-9d2a1bed28df",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-24T13:14:47.920336Z",
     "start_time": "2025-02-24T13:14:47.918190Z"
    }
   },
   "source": [
    "class InvalidAgeError(Exception):\n",
    "    def __init__(self, age, message=\"年龄必须在18到120之间\"):\n",
    "        self.age = age\n",
    "        self.message = message\n",
    "        super().__init__(self.message)\n",
    "\n",
    "def check_age(age):\n",
    "    if not 18 <= age <= 120:\n",
    "        raise InvalidAgeError(age)\n",
    "    else:\n",
    "        print(\"年龄合法\")\n",
    "\n",
    "try:\n",
    "    check_age(150)\n",
    "except InvalidAgeError as e:\n",
    "    print(f\"无效年龄：{e.age}，{e.message}\")"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "无效年龄：150，年龄必须在18到120之间\n"
     ]
    }
   ],
   "execution_count": 7
  },
  {
   "cell_type": "markdown",
   "id": "c5b41fc3-d21e-420f-8363-ff39e5830f98",
   "metadata": {},
   "source": [
    "- **说明**：定义了一个 `InvalidAgeError` 类，用于检查年龄是否在合理范围内。\n",
    "\n",
    "---\n",
    "\n",
    "## 6. 综合示例\n",
    "\n",
    "以下是一个综合示例，展示异常处理的多种用法："
   ]
  },
  {
   "cell_type": "code",
   "id": "6025667f-1d5d-4721-8343-113673adf30a",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-24T13:14:47.932444Z",
     "start_time": "2025-02-24T13:14:47.930110Z"
    }
   },
   "source": [
    "class InsufficientBalanceError(Exception):\n",
    "    def __init__(self, balance, amount, message=\"余额不足\"):\n",
    "        self.balance = balance\n",
    "        self.amount = amount\n",
    "        self.message = message\n",
    "        super().__init__(self.message)\n",
    "\n",
    "class BankAccount:\n",
    "    def __init__(self, balance=0):\n",
    "        self.balance = balance\n",
    "    \n",
    "    def withdraw(self, amount):\n",
    "        if amount > self.balance:\n",
    "            raise InsufficientBalanceError(self.balance, amount)\n",
    "        self.balance -= amount\n",
    "        return self.balance\n",
    "\n",
    "# 主程序\n",
    "account = BankAccount(100)\n",
    "try:\n",
    "    print(f\"当前余额：{account.balance}\")\n",
    "    account.withdraw(150)\n",
    "except InsufficientBalanceError as e:\n",
    "    print(f\"错误：{e.message}，余额：{e.balance}，尝试取出：{e.amount}\")\n",
    "else:\n",
    "    print(\"取款成功\")\n",
    "finally:\n",
    "    print(\"操作完成\")"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "当前余额：100\n",
      "错误：余额不足，余额：100，尝试取出：150\n",
      "操作完成\n"
     ]
    }
   ],
   "execution_count": 8
  },
  {
   "cell_type": "markdown",
   "id": "4091ebab-e779-4172-9a75-889621b40327",
   "metadata": {},
   "source": [
    "- **输出**（当余额不足时）：\n",
    "\n",
    "  ```\n",
    "  当前余额：100\n",
    "  错误：余额不足，余额：100，尝试取出：150\n",
    "  操作完成\n",
    "  ```\n",
    "\n",
    "- **说明**：定义了自定义异常 `InsufficientBalanceError`，并在银行账户取款时使用。\n",
    "\n",
    "---\n",
    "\n",
    "## 7. 总结\n",
    "\n",
    "- **异常**：程序运行时的错误事件。\n",
    "- **捕获异常**：使用 `try-except` 处理异常。\n",
    "- **`else`**：无异常时执行。\n",
    "- **`finally`**：无论如何都执行。\n",
    "- **抛出异常**：用 `raise` 手动引发异常。\n",
    "- **自定义异常**：继承 `Exception` 创建特定异常。"
   ]
  },
  {
   "cell_type": "code",
   "id": "87e05480-2b14-4032-9c96-761be885836f",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-24T13:14:47.945881Z",
     "start_time": "2025-02-24T13:14:47.944626Z"
    }
   },
   "source": [],
   "outputs": [],
   "execution_count": null
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda env:base] *",
   "language": "python",
   "name": "conda-base-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
